﻿///////////////////////////////////////////////////////
//
// XDesigner.ORM 
//
// autohr : yuans
//
// date: 2011-2-23
//
// email  : yyf9989@hotmail.com
// 
//
///////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;

namespace XDesigner.ORM.DOM
{
    [Serializable()]
    public class ORMProjectInfo
    {
        public ORMProjectInfo()
        {
        }

        private string _Name = "ORM Project";
        /// <summary>
        /// Project name
        /// </summary>
        [System.ComponentModel.DefaultValue( null)]
        public string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        private ORMTypeInfoList _Types = new ORMTypeInfoList();
        [System.Xml.Serialization.XmlArrayItem("Type" , typeof( ORMTypeInfo ))]
        public ORMTypeInfoList Types
        {
            get { return _Types; }
            set { _Types = value; }
        }

        private ORMDictionaryInfoList _Dictionaries = new ORMDictionaryInfoList();
        [System.Xml.Serialization.XmlArrayItem("Dictionary", typeof( ORMDictionaryInfo ))]
        public ORMDictionaryInfoList Dictionaries
        {
            get { return _Dictionaries; }
            set { _Dictionaries = value; }
        }

        public void AddTypes(Type[] types)
        {
            if (types == null)
            {
                throw new ArgumentNullException("types");
            }
            lock (this)
            {
                foreach (Type t in types)
                {
                    ORMTypeInfo tt = InnerAddType(t);
                }
                this.UpdateState();
            }
        }

        public ORMTypeInfo AddType(Type t)
        {
            if (t == null)
            {
                throw new ArgumentNullException("t");
            }
            lock (this)
            {
                ORMTypeInfo tt = InnerAddType(t);
                this.UpdateState();
                return tt;
            }
        }

        private ORMTypeInfo InnerAddType(Type t)
        {
            if (this.Types.Contains( t ))
            {
                return this.Types[t];
            }
            ORMTypeInfo tt = new ORMTypeInfo();
            tt.Load(t);
            tt.Project = this;
            this.Types.Add(tt);
            foreach (ORMPropertyInfo property in tt.Properties)
            {
                if (property.Ignore)
                {
                    continue;
                }
                if (property.HasRelation)
                {
                    Type pt = property.PropertyType;

                    if (CollectionTypeHelper.IsCollectionType(property.PropertyType))
                    {
                        pt = CollectionTypeHelper.GetElementType(property.PropertyType);
                    }
                    ORMTypeInfo childType = this.Types[pt];
                    if (childType == null)
                    {
                        childType = InnerAddType(pt);
                    }
                    // Set parent property of relation
                    //if (Util.HasContent(property.Relation.ParentPropertyName))
                    //{
                    //    property.Relation.ParentProperty = tt.Properties.GetByName(property.Relation.ParentPropertyName);
                    //}
                    //if (property.Relation.ParentProperty == null)
                    //{
                    //    property.Relation.ParentProperty = tt.KeyProperty;
                    //}
                    // Set child property of relation
                }
            }
            return tt;
        }

        public void UpdateState()
        {
            lock (this)
            {
                foreach (ORMTypeInfo type in this.Types)
                {
                    type.Project = this;
                    type.UpdateState();
                    foreach (ORMPropertyInfo p in type.Properties)
                    {
                        if (p.Ignore)
                        {
                            continue;
                        }
                        if (p.Relation == null && p.Overrideable )
                        {
                            Type pt = p.PropertyType;
                            bool isCollection = false;
                            if (CollectionTypeHelper.IsCollectionType(pt))
                            {
                                isCollection = true;
                                pt = CollectionTypeHelper.GetElementType(pt);
                            }
                            ORMTypeInfo opt = this.Types[pt];
                            if (opt != null)
                            {
                                p.Relation = new ORMRelationInfo();
                                if (isCollection)
                                {
                                    p.Relation.RuntimeStyle = ORMRelationStyle.OneToMany;
                                }
                                else
                                {
                                    p.Relation.RuntimeStyle = ORMRelationStyle.OneToOne;
                                }
                            }
                        }
                        if (p.Relation != null)
                        {
                            ORMTypeInfo t2 = null;
                            if (p.Relation.RuntimeStyle == ORMRelationStyle.OneToMany
                                || p.Relation.RuntimeStyle == ORMRelationStyle.OneToManyWithKeyList
                                || p.Relation.RuntimeStyle == ORMRelationStyle.OnetoManyExt )
                            {
                                t2 = this.Types[CollectionTypeHelper.GetElementType(p.PropertyType)];
                            }
                            else
                            {
                                t2 = this.Types[p.PropertyType];
                            }
                            if (t2 == null) System.Diagnostics.Debugger.Break();
                            p.Relation.ChildProperty =
                                t2.Properties.GetByName(p.Relation.ChildPropertyName);
                            if (p.Relation.ChildProperty == null)
                            {
                                foreach (ORMPropertyInfo p2 in t2.Properties)
                                {
                                    if (p2.PropertyType.Equals(type.InstanceType)
                                        || p2.PropertyType.IsSubclassOf( type.InstanceType ))
                                    {
                                        p.Relation.ChildProperty = p2;
                                        break;
                                    }
                                }
                                if (p.Relation.ChildProperty == null)
                                {
                                    p.Relation.ChildProperty = t2.KeyProperty;
                                }
                            }
                        }
                    }
                }//foreach
            }
        }

        private List<string> _SupportTables = new List<string>();
        /// <summary>
        /// Support data base table names
        /// </summary>
        public List<string> SupportTables
        {
            get
            {
                return _SupportTables; 
            }
            set
            {
                _SupportTables = value; 
            }
        }

        /// <summary>
        /// Merge information
        /// </summary>
        /// <param name="project"></param>
        /// <returns></returns>
        public bool Merge(ORMProjectInfo project)
        {
            if (project == null || project == this)
                return false;
            lock (this)
            {
                foreach (ORMTypeInfo t1 in project.Types)
                {
                    ORMTypeInfo t2 = this.Types[t1.InstanceTypeName];
                    if (t2 == null)
                    {
                        t2 = t1.Clone();
                        this.Types.Add(t2);
                    }
                    else
                    {
                        t2.Merge(t1);
                    }
                }
                return true;
            }
        }
    }
}
